home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / src890906.arc / EC.C < prev    next >
C/C++ Source or Header  |  1989-08-19  |  8KB  |  316 lines

  1. /* Driver for 3COM Ethernet card */
  2.  
  3. #define    TIMER    20000    /* Timeout on transmissions */
  4.  
  5. #include <stdio.h>
  6. #include <dos.h>
  7. #include "global.h"
  8. #include "mbuf.h"
  9. #include "enet.h"
  10. #include "iface.h"
  11. #include "ec.h"
  12. #include "timer.h"
  13. #include "arp.h"
  14. #include "trace.h"
  15. #include "pc.h"
  16.  
  17. static int ec_init __ARGS((struct iface *iface,unsigned bufsize));
  18. static int ec_raw __ARGS((struct iface *iface,struct mbuf *bp));
  19. static int ec_stop __ARGS((struct iface *iface));
  20. static void getecaddr __ARGS((unsigned base,char *cp));
  21. static void rcv_fixup __ARGS((unsigned base));
  22. static void setecaddr __ARGS((unsigned base,char *cp));
  23.  
  24. static INTERRUPT (*Ecvec[])() = {ec0vec,ec1vec,ec2vec};
  25. struct ec Ec[EC_MAX];        /* Per-controller info */
  26. unsigned Nec = 0;
  27.  
  28. /* Initialize interface */
  29. static int
  30. ec_init(iface,bufsize)
  31. struct iface *iface;
  32. unsigned bufsize;    /* Maximum size of receive queue in PACKETS */
  33. {
  34.     register struct ec *ecp;
  35.     register unsigned base;
  36.     int16 dev;
  37.  
  38.     dev = iface->dev;
  39.     ecp = &Ec[dev];
  40.     base = ecp->base;
  41.     ecp->iface = iface;
  42.  
  43.     /* Pulse IE_RESET */
  44.      outportb(IE_CSR(base),IE_RESET);
  45.  
  46.     /* Set interrupt vector */
  47.     if(setirq(ecp->vec,Ecvec[dev]) == -1){
  48.         printf("IRQ %u out of range\n",ecp->vec);
  49.         return -1;
  50.     }
  51.     maskon(ecp->vec);    /* Enable interrupt */
  52.     if(iface->hwaddr == NULLCHAR)
  53.         iface->hwaddr = malloc(EADDR_LEN);
  54.     getecaddr(base,iface->hwaddr);
  55.     setecaddr(base,iface->hwaddr);
  56.     if(memcmp(iface->hwaddr,Ether_bdcst,EADDR_LEN) == 0){
  57.         printf("EC address PROM contains broadcast address!!\n");
  58.         return -1;
  59.     }
  60.     /* Enable DMA/interrupt request, gain control of buffer */
  61.     outportb(IE_CSR(base),IE_RIDE|IE_SYSBFR);
  62.  
  63.     /* Enable transmit interrupts */
  64.     outportb(EDLC_XMT(base),EDLC_16 | EDLC_JAM);
  65.  
  66.     /* Set up the receiver interrupts and flush status */
  67.     outportb(EDLC_RCV(base),EDLC_MULTI|EDLC_GOOD|EDLC_ANY|EDLC_SHORT
  68.      |EDLC_DRIBBLE|EDLC_FCS|EDLC_OVER);
  69.     inportb(EDLC_RCV(base));
  70.  
  71.     /* Start receiver */
  72.     outportw(IE_RP(base),0);    /* Reset read pointer */
  73.     outportb(IE_CSR(base),IE_RIDE|IE_RCVEDLC);
  74.     return 0;
  75. }
  76. /* Send raw packet (caller provides header) */
  77. static int
  78. ec_raw(iface,bp)
  79. struct iface *iface;    /* Pointer to interface control block */
  80. struct mbuf *bp;        /* Data field */
  81. {
  82.     register struct ec *ecp;
  83.     register unsigned base;
  84.     register int i;
  85.     short size;
  86.  
  87.     dump(iface,IF_TRACE_OUT,TYPE_ETHER,bp);
  88.  
  89.     ecp = &Ec[iface->dev];
  90.     base = ecp->base;
  91.  
  92.     ecp->estats.xmit++;
  93.  
  94.     size = len_mbuf(bp);
  95.     /* Pad the size out to the minimum, if necessary,
  96.      * with junk from the last packet (nice security hole here)
  97.      */
  98.     if(size < RUNT)
  99.         size = RUNT;
  100.     size = (size+1) & ~1;    /* round size up to next even number */
  101.  
  102.     /* Wait for transmitter ready, if necessary. IE_XMTBSY is valid
  103.      * only in the transmit mode, hence the initial check.
  104.      */
  105.     if((inportb(IE_CSR(base)) & IE_BUFCTL) == IE_XMTEDLC){
  106.         for(i=TIMER;(inportb(IE_CSR(base)) & IE_XMTBSY) && i != 0;i--)
  107.             ;
  108.         if(i == 0){
  109.             ecp->estats.timeout++;
  110.             free_p(bp);
  111.             return -1;
  112.         }
  113.     }
  114.     ecp->size = size;
  115.     /* Get control of the board buffer and disable receiver */
  116.     outportb(IE_CSR(base),IE_RIDE|IE_SYSBFR);
  117.     /* Point GP at beginning of packet */
  118.     outportw(IE_GP(base),BFRSIZ-size);
  119.     /* Actually load each piece with a fast assembler routine */
  120.     while(bp != NULLBUF){
  121.         outbuf(IE_BFR(base),bp->data,bp->cnt);
  122.         bp = free_mbuf(bp);
  123.     }
  124.     /* Start transmitter */
  125.     outportw(IE_GP(base),BFRSIZ-size);
  126.     outportb(IE_CSR(base),IE_RIDE|IE_XMTEDLC);
  127.     return 0;
  128. }
  129. /* Ethernet interrupt handler */
  130. void
  131. ecint(dev)
  132. int dev;
  133. {
  134.     register struct ec *ecp;
  135.     register unsigned base;
  136.     struct mbuf *bp;
  137.     int16 size;
  138.     char stat;
  139.     struct phdr *phdr;
  140.  
  141.     ecp = &Ec[dev];
  142.     base = Ec[dev].base;
  143.     ecp->estats.intrpt++;
  144.  
  145.     /* Check for transmit jam */
  146.     if(!(inportb(IE_CSR(base)) & IE_XMTBSY)){
  147.         stat = inportb(EDLC_XMT(base));
  148.         if(stat & EDLC_16){
  149.             ecp->estats.jam16++;
  150.             rcv_fixup(base);
  151.         } else if(stat & EDLC_JAM){
  152.             /* Crank counter back to beginning and restart transmit */
  153.             ecp->estats.jam++;
  154.             outportb(IE_CSR(base),IE_RIDE|IE_SYSBFR);
  155.             outportw(IE_GP(base),BFRSIZ - ecp->size);
  156.             outportb(IE_CSR(base),IE_RIDE|IE_XMTEDLC);
  157.         }
  158.     }
  159.     for(;;){
  160.         stat = inportb(EDLC_RCV(base));
  161.         if(stat & EDLC_STALE)
  162.             break;
  163.  
  164.         if(stat & EDLC_OVER){
  165.             ecp->estats.over++;
  166.             rcv_fixup(base);
  167.             continue;
  168.         }
  169.         if(stat & (EDLC_SHORT | EDLC_FCS | EDLC_DRIBBLE)){
  170.             ecp->estats.bad++;
  171.             rcv_fixup(base);
  172.             continue;
  173.         }
  174.         if(stat & EDLC_ANY){
  175.             /* Get control of the buffer */
  176.             outportw(IE_GP(base),0);
  177.             outportb(IE_CSR(base),IE_RIDE|IE_SYSBFR);
  178.         
  179.             /* Allocate mbuf and copy the packet into it */
  180.             size = inportw(IE_RP(base));
  181.             if(size < RUNT || size > GIANT)
  182.                 ecp->estats.bad++;
  183.             else if((bp = alloc_mbuf(size+sizeof(struct phdr))) == NULLBUF)
  184.                 ecp->estats.nomem++;
  185.             else {
  186.                 ecp->estats.recv++;
  187.                 /* Generate descriptor header */
  188.                 phdr = (struct phdr *)bp->data;
  189.                 phdr->iface = ecp->iface;
  190.                 phdr->type = TYPE_ETHER;
  191.  
  192.                 inbuf(IE_BFR(base),bp->data+sizeof(struct phdr),size);
  193.                 bp->cnt = size + sizeof(struct phdr);
  194.                 enqueue(&Hopper,bp);
  195.             }
  196.             outportb(IE_CSR(base),IE_RIDE|IE_RCVEDLC);
  197.             outportb(IE_RP(base),0);
  198.         }
  199.     }
  200.     /* Clear any spurious interrupts */
  201.     (void)inportb(EDLC_RCV(base));
  202.     (void)inportb(EDLC_XMT(base));
  203. }
  204. static void
  205. rcv_fixup(base)
  206. register unsigned base;
  207. {
  208.     outportb(IE_CSR(base),IE_RIDE|IE_SYSBFR);
  209.     outportb(IE_CSR(base),IE_RIDE|IE_RCVEDLC);
  210.     outportb(IE_RP(base),0);
  211. }
  212. /* Read Ethernet address from controller PROM */
  213. static void
  214. getecaddr(base,cp)
  215. register unsigned base;
  216. register char *cp;
  217. {
  218.     register int i;
  219.  
  220.     for(i=0;i<EADDR_LEN;i++){
  221.         outportw(IE_GP(base),i);
  222.         *cp++ = inportb(IE_SAPROM(base));
  223.     }
  224. }
  225. /* Set Ethernet address on controller */
  226. static void
  227. setecaddr(base,cp)
  228. register unsigned base;
  229. register char *cp;
  230. {
  231.     register int i;
  232.  
  233.     for(i=0;i<EADDR_LEN;i++)
  234.         outportb(EDLC_ADDR(base)+i,*cp++);
  235. }
  236. /* Shut down the Ethernet controller */
  237. static int
  238. ec_stop(iface)
  239. struct iface *iface;
  240. {
  241.     register unsigned base;
  242.     int16 dev;
  243.  
  244.     dev = iface->dev;
  245.     base = Ec[dev].base;
  246.  
  247.     /* Disable interrupt */
  248.     maskoff(Ec[dev].vec);
  249.  
  250.     /* Pulse IE_RESET */
  251.     outportb(IE_CSR(base),IE_RESET);
  252.     outportb(IE_CSR(base),0);
  253.     return 0;
  254. }
  255. /* Attach a 3-Com model 3C500 Ethernet controller to the system
  256.  * argv[0]: hardware type, must be "3c500"
  257.  * argv[1]: I/O address, e.g., "0x300"
  258.  * argv[2]: vector, e.g., "3"
  259.  * argv[3]: mode, must be "arpa"
  260.  * argv[4]: interface label, e.g., "ec0"
  261.  * argv[5]: maximum number of packets allowed on receive queue, e.g., "5"
  262.  * argv[6]: maximum transmission unit, bytes, e.g., "1500"
  263.  */
  264. int
  265. ec_attach(argc,argv,p)
  266. int argc;
  267. char *argv[];
  268. void *p;
  269. {
  270.     register struct iface *if_ec;
  271.     unsigned dev;
  272.  
  273.     arp_init(ARP_ETHER,EADDR_LEN,IP_TYPE,ARP_TYPE,1,Ether_bdcst,pether,gether);
  274.     if(Nec >= EC_MAX){
  275.         printf("Too many Ethernet controllers\n");
  276.         return -1;
  277.     }
  278.     if(if_lookup(argv[4]) != NULLIF){
  279.         printf("Interface %s already exists\n",argv[4]);
  280.         return -1;
  281.     }
  282.     dev = Nec++;
  283.     if((if_ec = (struct iface *)calloc(1,sizeof(struct iface))) == NULLIF
  284.      ||(if_ec->name = strdup(argv[4])) == NULLCHAR){
  285.         printf("ec_attach: no memory!\n");
  286.         return -1;
  287.     }
  288.     if_ec->mtu = atoi(argv[6]);
  289.     if_ec->send = enet_send;
  290.     if_ec->output = enet_output;
  291.     if_ec->raw = ec_raw;
  292.     if_ec->stop = ec_stop;
  293.     if_ec->dev = dev;
  294.  
  295.     Ec[dev].base = htoi(argv[1]);
  296.     Ec[dev].vec = htoi(argv[2]);
  297.  
  298.     if(strcmp(argv[3],"arpa") != 0){
  299.         printf("Mode %s unknown for interface %s\n",
  300.             argv[3],argv[4]);
  301.         free(if_ec->name);
  302.         free((char *)if_ec);
  303.         return -1;
  304.     }
  305.     /* Initialize device */
  306.     if(ec_init(if_ec,(unsigned)atoi(argv[5])) != 0){
  307.         free(if_ec->name);
  308.         free((char *)if_ec);
  309.         return -1;
  310.     }
  311.     if_ec->next = Ifaces;
  312.     Ifaces = if_ec;
  313.  
  314.     return 0;
  315. }
  316.